﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;



namespace SOEN341_SCHEDULER_PHASE1
{
    [Serializable()]
    class Student : ISerializable
    {
        #region MEMBER_VARIABLES

        private string _email;
        private bool _isAdmin;
        private int _yearStudy;
        private string _firstName;
        private string _lastName;
        private long _id;
        private string _password;
        private List<Course> _pastCourses;
        private List<Course> _currentCourses;
        private EducationalProgram _program;
        public GlobalVariablesClass.ErrorCodes _errorCode;
        private string _programName;
        private Constraint _constraints;
        #endregion

        #region SERIALIZATION

        /// <summary>
        /// deserialization
        /// </summary>
        /// <param name="info"></param>
        /// <param name="ctxt"></param>
        public Student(SerializationInfo info, StreamingContext ctxt)
        {
            //Get the values from info and assign them to the appropriate properties

            _firstName = (string)info.GetValue("fname", typeof(string));
            _lastName = (string)info.GetValue("lname", typeof(string));
            _id = (long)info.GetValue("id", typeof(long));
            _password = (string)info.GetValue("password", typeof(string));
            _pastCourses = (List<Course>)info.GetValue("pastCourses", typeof(List<Course>));
            _currentCourses = (List<Course>)info.GetValue("currentCourses", typeof(List<Course>));
            //_program = (EducationalProgram)info.GetValue("program", typeof(EducationalProgram));
            _yearStudy = (int)info.GetValue("yearStudy", typeof(int));
            _isAdmin = (bool)info.GetValue("isAdmin", typeof(bool));
            _email = (string)info.GetValue("email", typeof(string));
            _programName = (string)info.GetValue("progName", typeof(string));
            _constraints = (Constraint)info.GetValue("constraint", typeof(Constraint));

        }

        /// <summary>
        /// serialization
        /// </summary>
        /// <param name="info"></param>
        /// <param name="ctxt"></param>
        public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            info.AddValue("fname", _firstName);
            info.AddValue("lname", _lastName);
            info.AddValue("id", _id);
            info.AddValue("password", _password);
            info.AddValue("pastCourses", _pastCourses);
            info.AddValue("currentCourses", _currentCourses);
            //info.AddValue("program", _program);
            info.AddValue("yearStudy", _yearStudy);
            info.AddValue("isAdmin", _isAdmin);
            info.AddValue("email", _email);
            info.AddValue("progName", _programName);
            info.AddValue("constraint", _constraints);
        }
        #endregion
        
        #region CONSTRUCTORS

        /// <summary>
        /// default constructor
        /// </summary>
        public Student()
        {
            _isAdmin = false;
            _firstName = "UNDEFINED";
            _lastName = "UNDEFINED";
            _id = -1;
            _password = "UNDEFINED";
            _pastCourses = new List<Course>();
            _currentCourses = new List<Course>();
            _program = null;
            _yearStudy = 0;
            _email = "NULL";

            _constraints = new Constraint();
        }

        /// <summary>
        /// parameterized constructor
        /// </summary>
        /// <param name="program">program registered in</param>
        /// <param name="firstName">student first name</param>
        /// <param name="lastName">student last name</param>
        /// <param name="id">student id</param>
        /// <param name="password">student password</param>
        /// <param name="pastCourses">list of past courses already taken (NULL if nothing)</param>
        /// <param name="yearStudy">current year of study</param>
        /// <param name="email">student email</param>
        public Student(EducationalProgram program, string firstName, string lastName, long id, string password, List<Course> pastCourses, int yearStudy, string email)
        {
            _email = email;
            _isAdmin = false;
            _yearStudy = yearStudy;
            _program = program;
            _firstName = firstName;
            _lastName = lastName;
            _id = id;
            _password = password;

            _pastCourses = new List<Course>();

            if (pastCourses != null)
            {
                Course[] courseTemp = pastCourses.ToArray();
                for (int i = 0; i < courseTemp.Length; i++)
                {
                    _pastCourses.Add(courseTemp[i]);
                }
            }

            _programName = program.GetName();

            _currentCourses = new List<Course>();

            _constraints = new Constraint();
        }

        #endregion

        /// <summary>
        /// Sets new courses (Replace)
        /// </summary>
        /// <param name="toSet">List of course to set</param>
        public void SetAllCourses(List<Course> toSet)
        {
            Course[] arrCourse = toSet.ToArray();
            _currentCourses.Clear();
            for (int i = 0; i < arrCourse.Length; i++)
            {
                _currentCourses.Add(arrCourse[i]);
            }
        }

        public void AddConstraint(CustomDateTime cdt)
        {
            _constraints.AddConstraint(cdt);
        }

        /// <summary>
        /// Set the program
        /// </summary>
        /// <param name="pg">Education program to set</param>
        public void SetProgram(EducationalProgram pg)
        {
            _program = pg;
        }

        /// <summary>
        /// Get the program name
        /// </summary>
        /// <returns>The program name</returns>
        public string GetProgramName()
        {
            return _programName;
        }

        /// <summary>
        /// sets student as admin or user
        /// </summary>
        /// <param name="isAdmin">TRUE: sets user as admin FALSE: sets user as student</param>
        public void SetAdmin(bool isAdmin)
        {
            _isAdmin = isAdmin;
        }

        /// <summary>
        /// adds a course
        /// </summary>
        /// <param name="course">course to add</param>
        /// <param name="overwrittenTaken">TRUE: add course even if alraedy taken in the past FALSE: adds course only if never taken</param>
        /// <returns>TRUE: Course added FALSE: not added (Course already taken) or student cannot register to course (check errorCodes)</returns>
        public bool AddCourse(Course course, bool overwrittenTaken)
        {
            //verify if taken
            if (!overwrittenTaken && IsTaken(course))
            {
                _errorCode = GlobalVariablesClass.ErrorCodes.Student_CourseAlreadyTaken;
                return false;
            }
            if (course.AddStudent(this))
            {
                _currentCourses.Add(course);
                return true;
            }
            else
            {
                _errorCode = course._errCode;
            }
            
            return false;
        }    

        /// <summary>
        /// verifies if course already taken
        /// </summary>
        /// <param name="course">course to check</param>
        /// <returns>TRUE: course already taken FALSE: course never taken</returns>
        public bool IsTaken(Course course)
        {
            return ((_pastCourses.Contains(course)) && (_currentCourses.Contains(course)));
        }

        /// <summary>
        /// sends email to student  (NOT IMPLEMENTED)
        /// </summary>
        /// <param name="subject">email subject</param>
        /// <param name="body">email body</param>
        /// <returns>TRUE: email sent FALSE: email not sent</returns>
        public bool SendEmail(string subject, string body)
        {
            //not implemented
            return false;
        }

        /// <summary>
        /// change student password
        /// </summary>
        /// <param name="password">password to change </param>
        public void ChangePassword(string password)
        {
            _password = password;
        }

        /// <summary>
        /// verifies user credentials
        /// </summary>
        /// <param name="id">user id to check</param>
        /// <param name="pw">user pw to check</param>
        /// <returns>TRUE: match FALSE: no match</returns>
        public bool VerifyCredentials(long id, string pw)
        {
            return ((_id == id) && (_password.Equals(pw)));
        }

        /// <summary>
        /// Adds a past course taken
        /// </summary>
        /// <param name="toAdd">Course to add</param>
        /// <returns>TRUE: ADDED FALSE: NOT ADDED (CHECK _errorCode)</returns>
        public bool AddPastCourse(Course toAdd)
        {
            if (!_pastCourses.Contains(toAdd))
            {
                _pastCourses.Add(toAdd);
                return true;
            }
            _errorCode = GlobalVariablesClass.ErrorCodes.Student_CourseAlreadyTaken;
            return false;
        }

        #region ACCESSORS
               
        /// <summary>
        /// checks if student is admin
        /// </summary>
        /// <returns>TRUE: admin FALSE: not admin</returns>
        public bool IsAdmin()
        {
            return _isAdmin;
        }

        public Constraint GetConstraints()
        {
            return _constraints;
        }
        /// <summary>
        /// returns user program
        /// </summary>
        /// <returns>returns EducationProgram of user</returns>
        public EducationalProgram GetProgram()
        {
            return _program;
        }

        /// <summary>
        /// returns first name of student
        /// </summary>
        /// <returns>first name of student</returns>
        public string GetFirstName()
        {
            return _firstName;
        }

        /// <summary>
        /// returns last name of student
        /// </summary>
        /// <returns>last name</returns>
        public string GetLastName()
        {
            return _lastName;
        }

        /// <summary>
        /// get current year of study
        /// </summary>
        /// <returns>year of study</returns>
        public int GetYearOfStudy()
        {
            return _yearStudy;
        }

        /// <summary>
        /// get student id
        /// </summary>
        /// <returns>student id</returns>
        public long GetID()
        {
            return _id;
        }

        /// <summary>
        /// get current courses registered for
        /// </summary>
        /// <returns>list of current courses</returns>
        public List<Course> GetCurrentCourses()
        {
            return _currentCourses;
        }

        /// <summary>
        /// get course history of student
        /// </summary>
        /// <returns>list of course history</returns>
        public List<Course> GetCourseHistory()
        {
            //create a copy
            List<Course> temp = new List<Course>();

            Course[] tempArr = _pastCourses.ToArray();

            for (int i = 0; i < tempArr.Length; i++)
            {
                temp.Add(tempArr[i]);
            }

            return temp;
        }

        /// <summary>
        /// gets student email
        /// </summary>
        /// <returns>student email</returns>
        public string GetEmail()
        {
            return _email;
        }

        /// <summary>
        /// to string
        /// </summary>
        /// <returns>returns student info</returns>
        public override string ToString()
        {
            return _firstName + " "+_lastName+" - ID# " + _id.ToString();
        }
        #endregion

    }
}
